package loaders
{
	import event.ResEvent;
	
	import flash.display.DisplayObject;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.net.URLRequest;
	import flash.system.ApplicationDomain;
	import flash.system.LoaderContext;
	import flash.utils.Dictionary;
	
	/**
	 * 加载并管理资源缓存。这里需要找下原因，一个出错会导致所有NPC无法正常加载。
	 * @author Ryan
	 * 
	 */
	public class ResCacher extends EventDispatcher
	{
		private static var _instance:ResCacher = null;
		
		private var _tResCache:Dictionary = new Dictionary();
		private var _tResLoadingList:Dictionary = new Dictionary();
		private var _pResCache:Dictionary = new Dictionary();
		private var _pResLoadingList:Dictionary = new Dictionary();
		
		public var current_complete_loader:LoaderInfo;
		
		private var _permanentDomain : ApplicationDomain;
		private var _temporaryDomain : ApplicationDomain;
		
		private var _resourceRoot : String = null;
		
		public static function getInstance():ResCacher
		{
			if(!_instance) 
			{
				_instance = new ResCacher();
			} 	
			return _instance;
		}
		
		public function get permanentDomain():ApplicationDomain
		{
			return _permanentDomain;
		}
		
		public function set permanentDomain( value:ApplicationDomain ):void
		{
			_permanentDomain = value;
		}
		
		public function get temporaryDomain():ApplicationDomain
		{
			return _temporaryDomain;
		}
		
		public function set temporaryDomain( value:ApplicationDomain ):void
		{
			_temporaryDomain = value;
		}
		
		public function clear():void
		{
			_tResCache = new Dictionary();
		}
		
		public function get resourceRoot():String
		{
			return _resourceRoot;
		}
		
		public function set resourceRoot( value:String):void
		{
			_resourceRoot = value;
		}
		
		public function fetchResource( url:String, loadToPermanentDomain:Boolean = false ):DisplayObject
		{
			var cache :Dictionary = loadToPermanentDomain ? this._pResCache : this._tResCache;
			var loadingList :Dictionary = loadToPermanentDomain ? this._pResLoadingList : this._tResLoadingList;

			var resource:DisplayObject = DisplayObject(cache[url]);
			
			if (resource)
			{
				return resource;
			}
			else if(!loadingList[url])
			{
				var loader:Loader = new Loader();
				loadingList[url] = loader;
				
				loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
				loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,errorHandler);
				
				var targetDomain : ApplicationDomain = loadToPermanentDomain ? this._permanentDomain : this._temporaryDomain;
				loader.load(new URLRequest(_resourceRoot+url), new LoaderContext(false, targetDomain));
			}
			return null;
		}
		
		private function getType(url:String):String
		{
			return url.substr(url.lastIndexOf(_resourceRoot));
		}
		
		private function errorHandler(e:IOErrorEvent):void
		{
			var loaderInfo:LoaderInfo = LoaderInfo(e.target);
			
			loaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, errorHandler);
			loaderInfo.removeEventListener(Event.COMPLETE, completeHandler);
			
			var loader:Loader = Loader(loaderInfo.loader);
			for (var urlAlias:String in _tResLoadingList)
			{
				if (_tResLoadingList[urlAlias] == loader)
				{
					trace("ResCacher: load resoure error, URL: "+urlAlias);
					delete _tResLoadingList[urlAlias];
					break;
				}
			}
		}
		
		private function completeHandler(e:Event):void 
		{
			var loaderInfo:LoaderInfo = LoaderInfo(e.target);
			
			current_complete_loader = loaderInfo;
			
			loaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, errorHandler);
			loaderInfo.removeEventListener(Event.COMPLETE, completeHandler);
			
			var urlAlias:String = getUrlAlias(loaderInfo.url);
			delete _tResLoadingList[urlAlias];
			
			_tResCache[urlAlias] = loaderInfo.content;
			dispatchEvent(new ResEvent( this.getUrlAlias (loaderInfo.url), loaderInfo.content));
		}
		
		private function getUrlAlias(url:String):String
		{
			var rootPath:* = _resourceRoot.substr(0, 1) == '.' ? _resourceRoot.substr(1) : _resourceRoot; 
			return url.substr(url.lastIndexOf(rootPath) + rootPath.length);
		}
	}
}